/**
 * \file LeftExpression.cpp
 * \brief Implementation of Expression subclasses which can be assigned to
 * \author Wouter Caarls <w.caarls@tnw.tudelft.nl> 
 *
 * \verbatim
 * Copyright (c) 2005 Wouter Caarls, Delft University of Technology
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * \endverbatim
 */

#include "Symbol.h"
#include "Expression.h"
#include "LeftExpression.h"
#include "Code.h"

std::string Id::toString(int indentation)
{
  return (char*)(CStr(indent(indentation)) << name);
}

std::string Id::toTerm()
{
  return (char*)(CStr("Id(\"") << name << "\")");
}

void Id::findStorage(SymbolTable *symbols, Compound *out,
		     std::list<Value**> &storage, std::list<Value**> &path)
{
  Variable *var = dynamic_cast<Variable*>(symbols->findSymbol(name));

  if (var)
  {
    storage.push_back(&var->data);
    path.push_back(&var->data);
  }
  else
  {
    if (name != "*")
      plog.notice() << HDR << "could not find storage for unknown identifier " << name
		    << std::endl;
  }
}

LeftExpression* Id::buildStoragePath(SymbolTable *symbols, Compound *out)
{
  Variable *var = dynamic_cast<Variable*>(symbols->findSymbol(name));
  if (var)
    type = var->data->type;

  return this->copy();
}

void Id::residualizeStoragePath(SymbolTable *symbols)
{
}

LeftExpression* Id::anonimizeStoragePath(int tindex)
{
  return new IndexedSymbol(type, tindex);
}

Id *Id::findId(SymbolTable *symbols)
{
  return this->copy();
}

/* ************************************************************************* */

std::string Deref::toString(int indentation)
{
  return (char*)(CStr(indent(indentation)) << "*(" << data->toString() << ")");
}

std::string Deref::toTerm()
{
  return (char*)(CStr("Deref(") << data->toTerm() << ")");
}

void Deref::findStorage(SymbolTable *symbols, Compound *out,
			std::list<Value**> &storage, std::list<Value**> &path)
{
  std::list<Value**> substorage, subpath;
  LeftExpression *ldata = dynamic_cast<LeftExpression*>(data);
  Expression *res=NULL;
  Value *vdata=NULL;

  LOG(plog.crawl, HDR << "finding Deref storage for " << toString() << std::endl);

  if (ldata)
  {
    ldata->findStorage(symbols, out, substorage, subpath);
  }
  else
  {
    /* We're dereferencing an expression */
    res = data->reduce(symbols, out, AsExpression);
    vdata = dynamic_cast<Value*>(res);

    if (vdata)
      substorage.push_back(&vdata);
    else
    {
      LOG(plog.debug, HDR << "Dereferencing unknown expression '" << res->toString() << "'" << std::endl);
      delete res;
    }
  }
  
  if (!substorage.empty())
  {
    for (SI ii = substorage.begin(); ii != substorage.end(); ++ii)
    {
      PointerValue *ptr = dynamic_cast<PointerValue*>(**ii);
      
      if (!ptr)
      {
	/* Dereferencing an array */
	ArrayValue *arr = dynamic_cast<ArrayValue*>(**ii);
	if (!arr)
        {
          CLogStream *stream;
          if (typeid(*((**ii)->type)) != typeid(Unknown))
            stream = &plog.warning;
          else
            stream = &plog.crawl;

  	  LOG(*stream, HDR << "Dereferencing neither array nor pointer '" << toString() << "'" << std::endl);
        }
        else
        {
  	  storage.push_back(arr->data[0]);
	  path.push_back(arr->data[0]);
        }
      }
      else
      {
	for (PointerValue::TI ti=ptr->to.begin(); ti != ptr->to.end(); ++ti)
	{
	  Variable *var = dynamic_cast<Variable*>(symbols->getSymbol(ti->index));
	  if (var)
	  {
	    LeftExpression *anonpath = ti->route->anonimizeStoragePath(ti->index);
	    
	    if (ptr->type == ti->route->type)
	    {
	      /* Dereferencing a pointer to an array */
	      PointerType *ptrtype = dynamic_cast<PointerType*>(ptr->type);
	      if (!ptrtype)
		error("Internal type mismatch");
	      
	      anonpath = new ArrayIndex(ptrtype->to, anonpath, new IntegerValue(0));
	    }
	    
	    std::list<Value**> rstorage, rpath;
	    anonpath->findStorage(symbols, out, rstorage, rpath);
	    
	    delete anonpath;
	    
	    if (!rstorage.empty())
	      for (SI jj = rstorage.begin(); jj != rstorage.end(); ++jj)
	      {
		storage.push_back((*jj));
		path.push_back((*jj));
	      }
	    
	    if (!rpath.empty())
	      for (SI jj = rpath.begin(); jj != rpath.end(); ++jj)
		path.push_back((*jj));
	    
	  }
	  else
	    // *** SHOULD RETURN SOME KIND OF DUMMY ***
	    LOG(plog.debug, HDR << "Dereferencing pointer to unknown variable at index "
			 << ti->index << std::endl);
	}
      }
      
      if (ldata)
	path.push_back((*ii));
    }
  }
  
  if (!subpath.empty())
    for (SI jj = subpath.begin(); jj != subpath.end(); ++jj)
      path.push_back((*jj));
  
  if (vdata)
    delete vdata;
}

LeftExpression* Deref::buildStoragePath(SymbolTable *symbols, Compound *out)
{
  LeftExpression *ldata = dynamic_cast<LeftExpression*>(data);
  Expression *res;

  if (ldata)
    res = ldata->buildStoragePath(symbols, out);
  else
    // *** EXPRESSION RETURNING CODE ***
    res = data->reduce(symbols, out, AsExpression);

  PointerType *ptrtype = dynamic_cast<PointerType*>(res->type);
  if (!ptrtype)
  {
    CLogStream *stream;
    if (typeid(*(res->type)) != typeid(Unknown))
      stream = &plog.warning;
    else
      stream = &plog.crawl;

    LOG(*stream, HDR << "Dereferencing neither array nor pointer '" << toString() << "'" << std::endl);

    type = &Unknown;
  }
  else
    type = ptrtype->to;

  return new Deref(type, res);
}

void Deref::residualizeStoragePath(SymbolTable *symbols)
{
  LeftExpression *ldata = dynamic_cast<LeftExpression*>(data);

  if (ldata)
    ldata->residualizeStoragePath(symbols);
  else
    data->residualize(symbols);
}

LeftExpression* Deref::anonimizeStoragePath(int tindex)
{
  LeftExpression *ldata = dynamic_cast<LeftExpression*>(data);

  if (ldata)
    return new Deref(type, ldata->anonimizeStoragePath(tindex));
  else
    return new Deref(type, data->copy());
}

Id *Deref::findId(SymbolTable *symbols)
{
  LeftExpression *ldata = dynamic_cast<LeftExpression*>(data);
  PointerValue *pdata=dynamic_cast<PointerValue*>(data);
  Address *adata=dynamic_cast<Address*>(data);

  if (ldata)
    return ldata->findId(symbols);
  else if (pdata)
  {
    // *** TODO: SHOULD RETURN ALL IDs ***
    return pdata->to[0].route->findId(symbols);
  }
  else if (adata)
    return adata->data->findId(symbols);

  // *** TODO: TYPECAST ***

//  plog.warning() << HDR << "invalid data type " << typeid(*data).name()
//		 << " for dereference" << std::endl;

  return new Id();
}

/* ************************************************************************* */

std::string Decode::toString(int indentation)
{
  return (char*)(CStr(indent(indentation)) << "(@(" << data->toString() << "))");
}

std::string Decode::toTerm()
{
  return (char*)(CStr("Decode(") << data->toTerm() << ")");
}

Expression *Decode::reduce(SymbolTable *symbols, Compound *out, Use use)
{
  Expression *res = data->reduce(symbols, out, AsExpression);
  CodeValue *code = dynamic_cast<CodeValue*>(res);

  if (code)
  {
    Code *res2 = code->data->reduce(symbols, out, use);
    Expression *exp = dynamic_cast<Expression*>(res2);
    
    delete res;

    if (exp)
      return exp;
    else
      error("Decoded value doesn't reduce to an expression");
  }
  else if (res->known)
  {
    LOG(plog.warning, HDR << "Decoding a non-code value '" << res->toString() << "'"
	<< std::endl);
    return res;
  }
  else
    return new Decode(&Unknown, res);

  /* Not reached */
  return copy();
}

void Decode::findStorage(SymbolTable *symbols, Compound *out,
			std::list<Value**> &storage, std::list<Value**> &path)
{
  std::list<Value**> substorage, subpath;
  LeftExpression *ldata = dynamic_cast<LeftExpression*>(data);
  Expression *res=NULL;
  Value *vdata=NULL;

  LOG(plog.crawl, HDR << "finding Decode storage for " << toString() << std::endl);

  if (ldata)
  {
    ldata->findStorage(symbols, out, substorage, subpath);
  }
  else
  {
    /* We're decoding an expression */
    res = data->reduce(symbols, out, AsExpression);
    vdata = dynamic_cast<CodeValue*>(res);

    if (vdata)
      substorage.push_back(&vdata);
    else
    {
      LOG(plog.warning, HDR << "Decoding an expression yielding no code '" << res->toString() << "'" << std::endl);
      delete res;
    }
  }
  
  if (substorage.size() != 1)
  {
    LOG(plog.warning, HDR << "Expression to decode is unknown '" << toString() << "'"
	<< std::endl);
  }

  if (!substorage.empty())
  {
    for (SI ii = substorage.begin(); ii != substorage.end(); ++ii)
    {
      CodeValue *code = dynamic_cast<CodeValue*>(**ii);
      
      if (!code)
      {
	LOG(plog.warning, HDR << "Decoding a non-code value '" << toString() << "'" << std::endl);
      }
      else
      {
	LeftExpression *cldata = dynamic_cast<LeftExpression*>(code->data);

	if (cldata)
	{
	  std::list<Value**> rstorage, rpath;

	  cldata->findStorage(symbols, out, rstorage, rpath);

	  if (!rstorage.empty())
	    for (SI jj = rstorage.begin(); jj != rstorage.end(); ++jj)
	    {
	      storage.push_back((*jj));
	      path.push_back((*jj));
	    }
	  
	  if (!rpath.empty())
	    for (SI jj = rpath.begin(); jj != rpath.end(); ++jj)
	      path.push_back((*jj));
	}
	else
	{
	  LOG(plog.warning, HDR << "Code doesn't decode to leftexpression '" << toString() << "'" << std::endl); 
	}

	if (ldata)
	  path.push_back(*ii);
      }
    }
  }
  
  if (!subpath.empty())
    for (SI jj = subpath.begin(); jj != subpath.end(); ++jj)
      path.push_back((*jj));
  
  if (vdata)
    delete vdata;
}

LeftExpression* Decode::buildStoragePath(SymbolTable *symbols, Compound *out)
{
  LeftExpression *ldata = dynamic_cast<LeftExpression*>(data);
  LeftExpression *res;
  CodeValue *code=NULL;

  if (ldata)
  {
    std::list<Value**> storage, path;
    
    res = ldata->buildStoragePath(symbols, out);
    res->findStorage(symbols, out, storage, path);

    if (storage.size() == 1)
      code = dynamic_cast<CodeValue*>(**storage.begin());
    else
      error("Expression to decode is unknown");
  }
  else
  {
    // *** EXPRESSION RETURNING CODE ***
    code = dynamic_cast<CodeValue*>(data->reduce(symbols, out, AsExpression));
  }
  
  if (code)
  {
    LeftExpression *cldata = dynamic_cast<LeftExpression*>(code->data);
    
    if (cldata)
    {
      LeftExpression *clpath = cldata->buildStoragePath(symbols, out);
      
      type = clpath->type;

      return clpath;
    }
    else
      error("Code doesn't decode to leftexpression");
  }
  else
    error("Decoding a non-code value");

  return copy();
}

void Decode::residualizeStoragePath(SymbolTable *symbols)
{
  if (data)
    data->residualize(symbols);
}

LeftExpression* Decode::anonimizeStoragePath(int tindex)
{
  LOG(plog.warning, HDR << "Cannot anonimize Decode" << std::endl);  
  return new Decode(type, data->copy());
}

Id *Decode::findId(SymbolTable *symbols)
{
  return new Id();
}

/* ************************************************************************* */

std::string ArrayIndex::toString(int indentation)
{
  return (char*)(CStr(indent(indentation)) << "(" << data->toString() << ")[" << index->toString() << "]");
}

std::string ArrayIndex::toTerm()
{
  return (char*)(CStr("ArrayIndex(") << data->toTerm() << ", " << index->toTerm() << ")");
}

void ArrayIndex::findStorage(SymbolTable *symbols, Compound *out,
			     std::list<Value**> &storage, std::list<Value**> &path)
{
  std::list<Value**> substorage, subpath;

  LOG(plog.crawl,HDR << "finding ArrayIndex storage for " << toString() << std::endl);

  data->findStorage(symbols, out, substorage, subpath);

  Expression *indexp = index->reduce(symbols, out, AsExpression);

  for (SI ii = substorage.begin(); ii != substorage.end(); ++ii)
  {
    PointerValue *ptr = dynamic_cast<PointerValue*>(**ii);
    if (ptr)
    {
      /* Indexing a pointer. This means the pointer should point to an ArrayValue. */
      for (PointerValue::TI ti=ptr->to.begin(); ti != ptr->to.end(); ti++)
      {
	LOG(plog.debug, HDR << "Indexing pointer at index " << ti->index
		     << std::endl);

	Variable *var = dynamic_cast<Variable*>(symbols->getSymbol(ti->index));
	if (var)
	{
	  LeftExpression *anonpath = ti->route->anonimizeStoragePath(ti->index);

	  std::list<Value**> rstorage, rpath;
	  anonpath->findStorage(symbols, out, rstorage, rpath);
	
	  delete anonpath;
	
	  if (!rstorage.empty())
	    for (SI jj = rstorage.begin(); jj != rstorage.end(); ++jj)
	    {
	      LOG(plog.crawl,HDR << "pushing " << (**jj)->toString() << std::endl);

	      substorage.push_back((*jj));
	      subpath.push_back((*jj));
	    }
	}
	else
	  // *** SHOULD RETURN SOME KIND OF DUMMY ***
	  LOG(plog.debug, HDR << "Indexing pointer to unknown variable at index "
		       << ti->index << std::endl);
      }
    }
    else
    {
      ArrayValue *arr = dynamic_cast<ArrayValue*>(**ii);

      if (arr)
      {
        PointerType *arrtype = dynamic_cast<PointerType*>(arr->type);
  
        if (indexp->known)
        {
  	  /* If index expression is known, return only indexed value. */
  	  Value *indval = dynamic_cast<Value*>(indexp);
	
	  int index = indval->castToInteger();
	  if (index < 0 || (index >= (int)arr->data.size() && arrtype->elements != -1))
	    error(CStr("Index ") << index << " out of range");

	  if (index >= (int)arr->data.size() && arrtype->elements == -1)
	  {
	    /* Resize to fit */
	    LOG(plog.crawl,HDR << "Resizing variable length array to " << index + 1
	  	         << std::endl);

	    while ((int)arr->data.size() <= index)
	      arr->data.push_back(new Value*(arrtype->to->makeValue()));
	  }

	  storage.push_back(arr->data[index]);
	  path.push_back(arr->data[index]);
        }
        else
        {
	  /* Otherwise, return all values */
	  ArrayValue::EI jj;
	  for (jj = arr->data.begin(); jj != arr->data.end(); ++jj)
	  {
	    storage.push_back((*jj));
	    path.push_back((*jj));
	  }
        }
      }
      else
      {
        VoidValue *vd = dynamic_cast<VoidValue*>(**ii);;
        if (vd)
        {
          LOG(plog.crawl,HDR << "Indexing a void" << std::endl);
          /*EmptyExp*/;
        }
        else
        {
          CLogStream *stream;
          if (typeid(*((**ii)->type)) != typeid(Unknown))
            stream = &plog.warning;
          else
            stream = &plog.crawl;

          LOG(*stream, HDR << "Indexing neither array nor pointer '" << toString() << "'" << std::endl);
        }
      }
    }

    path.push_back((*ii));
  }

  if (!subpath.empty())
    for (SI jj = subpath.begin(); jj != subpath.end(); ++jj)
      path.push_back((*jj));
}

LeftExpression* ArrayIndex::buildStoragePath(SymbolTable *symbols, Compound *out)
{
  LOG(plog.crawl,HDR << "building ArrayIndex storage path for " << toString() << std::endl);

  Expression *indexp = index->reduce(symbols, out, AsExpression);
  LeftExpression *res;

  res = data->buildStoragePath(symbols, out);

  LOG(plog.crawl,HDR << "res is " << res->toString() << std::endl);

  PointerType *restype = dynamic_cast<PointerType*>(res->type);

  if (restype)
    type = restype->to;

  return new ArrayIndex(type, res, indexp);
}

void ArrayIndex::residualizeStoragePath(SymbolTable *symbols)
{
  index->residualize(symbols);
  data->residualizeStoragePath(symbols);
}

LeftExpression* ArrayIndex::anonimizeStoragePath(int tindex)
{
  if (index->known)
    return new ArrayIndex(type, data->anonimizeStoragePath(tindex), index->copy());
  else
    return new ArrayIndex(type, data->anonimizeStoragePath(tindex),
			  new Id(&BasicInteger, "*"));
}

Id *ArrayIndex::findId(SymbolTable *symbols)
{
  return data->findId(symbols);
}

/* ************************************************************************* */

std::string Field::toString(int indentation)
{
  return (char*)(CStr(indent(indentation)) << "(" << data->toString() << ")."
		 << member->toString());
}

std::string Field::toTerm()
{
  return (char*)(CStr("Field(") << data->toTerm() << ", " << member->toTerm() << ")");
}

void Field::findStorage(SymbolTable *symbols, Compound *out,
			std::list<Value**> &storage, std::list<Value**> &path)
{
  std::list<Value**> substorage, subpath;

  data->findStorage(symbols, out, substorage, subpath);

  Id *memid = DecodeId(member, symbols, out);

  for (SI ii = substorage.begin(); ii != substorage.end(); ++ii)
  {
    StructValue *str = dynamic_cast<StructValue*>(**ii);
    if (!str)
    {
      CLogStream *stream;
      if (typeid(*((**ii)->type)) != typeid(Unknown))
        stream = &plog.warning;
      else
        stream = &plog.crawl;

      LOG(*stream, HDR << "'" << type->toString() << "' is not a structure" << std::endl);
    }
    else
    {
      StructType *strtype = dynamic_cast<StructType*>(str->type);
      if (!strtype)
        error("Internal type mismatch");

      /* Find index of member in type */
      int memind = strtype->findMemberIndex(memid->name);
      if (memind < 0)
        error(CStr("'") << memid->name << "' is not a member of '" << type->toString()
  		   << "'");

      storage.push_back(str->data[memind]);
      path.push_back(str->data[memind]);
    }

    path.push_back((*ii));
  }

  if (!subpath.empty())
    for (SI jj = subpath.begin(); jj != subpath.end(); ++jj)
      path.push_back((*jj));

  delete memid;
}

LeftExpression* Field::buildStoragePath(SymbolTable *symbols, Compound *out)
{
  LeftExpression *res;

  res = data->buildStoragePath(symbols, out);

  Id *memid = DecodeId(member, symbols, out);

  StructType *strtype = dynamic_cast<StructType*>(res->type);
  if (!strtype)
  {
    CLogStream *stream;
    if (typeid(*(res->type)) != typeid(Unknown))
      stream = &plog.warning;
    else
      stream = &plog.crawl;

    LOG(*stream, HDR << "Taking member of non-structure " << res->toString() << std::endl);

    type = &Unknown;
  }
  else
  {
    int memind = strtype->findMemberIndex(memid->name);
    if (memind < 0)
      error(CStr("'") << memid->name << "' is not a member of '" << type->toString()
  	         << "'");
	  
    type = strtype->subtypes[memind]->type;
  }

  return new Field(type, res, memid);
}

void Field::residualizeStoragePath(SymbolTable *symbols)
{
  data->residualizeStoragePath(symbols);
}

LeftExpression* Field::anonimizeStoragePath(int tindex)
{
  return new Field(type, data->anonimizeStoragePath(tindex), member->copy());
}

Id *Field::findId(SymbolTable *symbols)
{
  return data->findId(symbols);
}

/* ************************************************************************* */

std::string IndexedSymbol::toString(int indentation)
{
  return "";
}

std::string IndexedSymbol::toTerm()
{
  return (char*)(CStr("Id(\"<symbol at index ") << index << ">\")");
}

void IndexedSymbol::findStorage(SymbolTable *symbols, Compound *out,
				std::list<Value**> &storage, std::list<Value**> &path)
{
  Variable *var = dynamic_cast<Variable*>(symbols->getSymbol(index));

  if (var != NULL)
  {
    LOG(plog.debug, HDR << "variable is " << var->toString() << std::endl);

    std::list<Value**> res;

    storage.push_back(&var->data);
    path.push_back(&var->data);
  }
  else
    plog.warning() << HDR << "illegal storage location at index " << index << std::endl;
}

LeftExpression* IndexedSymbol::buildStoragePath(SymbolTable *symbols, Compound *out)
{
  plog.warning() << HDR << "found IndexedSymbol while building storage path"
		 << std::endl;

  Variable *var = dynamic_cast<Variable*>(symbols->getSymbol(index));

  if (var)
    type = var->data->type;

  return this->copy();
}

void IndexedSymbol::residualizeStoragePath(SymbolTable *symbols)
{
}

LeftExpression* IndexedSymbol::anonimizeStoragePath(int tindex)
{
  plog.warning() << HDR << "found IndexedSymbol while anonimizing storage path"
		 << std::endl;

  return this->copy();
}

Id *IndexedSymbol::findId(SymbolTable *symbols)
{
  Variable *var = dynamic_cast<Variable*>(symbols->getSymbol(index));

  return new Id(type, var->identifier);
}

/* ************************************************************************* */

std::string XTCArrayIndex::toString(int indentation)
{
  return (char*)(CStr(indent(indentation)) << data->toString() << "[" << lindex->toString() << " .. " << rindex->toString() << "]");
}

std::string XTCArrayIndex::toTerm()
{
  return (char*)(CStr("XTCArrayIndex(") << data->toTerm() << ", " << lindex->toTerm() << ", " << rindex->toTerm() << ")");
}

void XTCArrayIndex::findStorage(SymbolTable *symbols, Compound *out,
				std::list<Value**> &storage, std::list<Value**> &path)
{
}

LeftExpression* XTCArrayIndex::buildStoragePath(SymbolTable *symbols, Compound *out)
{
  LOG(plog.crawl, HDR << "building XTCArrayIndex storage path for " << toString() << std::endl);
  
  Expression *lindexp = lindex->reduce(symbols, out, AsExpression);
  Expression *rindexp = rindex->reduce(symbols, out, AsExpression);
  LeftExpression *res;
  
  res = data->buildStoragePath(symbols, out);
  
  LOG(plog.crawl, HDR << "res is " << res->toString() << std::endl);
  
  PointerType *restype = dynamic_cast<PointerType*>(res->type);
  
  if (restype)
    type = restype->to;
  
  return new XTCArrayIndex(type, res, lindexp, rindexp);
}

void XTCArrayIndex::residualizeStoragePath(SymbolTable *symbols)
{
  data->residualizeStoragePath(symbols);
}

LeftExpression* XTCArrayIndex::anonimizeStoragePath(int tindex)
{
  Expression *newlindex, *newrindex;
  
  if (lindex->known) newlindex = lindex->copy();
  else               newlindex = new Id(&BasicInteger, "*");
  if (rindex->known) newrindex = rindex->copy();
  else               newrindex = new Id(&BasicInteger, "*");
  
  return new XTCArrayIndex(type, data->anonimizeStoragePath(tindex),
			   newlindex, newrindex);
}

Id *XTCArrayIndex::findId(SymbolTable *symbols)
{
  return data->findId(symbols);
}

bool XTCArrayIndex::hasSideEffects()
{ 
  return data->hasSideEffects() || lindex->hasSideEffects() || rindex->hasSideEffects();
}

/* ************************************************************************* */

std::string Escape::toString(int indentation)
{
  return (char*)(CStr(indent(indentation)) << "$(" << data->toString() << ")");
}

std::string Escape::toTerm()
{
  return (char*)(CStr("Escape(") << data->toTerm() << ")");
}

Expression *Escape::replace(Code *src, Code *rplc,
		    SymbolTable *symbols, Compound *out)
{
  if (typeid(*src) == typeid(Escape))
  {
    Decode *ddata = dynamic_cast<Decode*>(data);

    if (ddata)
    {
      /* $@x reduces to the contents of the reduction of x */
      Expression *res = ddata->data->reduce(symbols, out, AsExpression);
      CodeValue *dcode = dynamic_cast<CodeValue*>(res);

      /* If x is no code, just return its reduction */
      if (!dcode)
	return res->reduce(symbols, out, AsExpression);

      Expression *dcodexp = dynamic_cast<Expression*>(dcode->data);

      /* If returned code is no expression, just return its decoding */
      if (!dcodexp)
	return new Decode(&Unknown, dcode);

      return dcodexp;
    }
    else
    {
      /* $x reduces to the reduction of x */
      Expression *res = data->reduce(symbols, out, AsExpression);
      if (!res->known)
        error("Cannot splice unknown value");
      return res;
    }
  }
  else
    return new Escape(type, data->replace(src, rplc, symbols, out));
}      

Expression *Escape::reduce(SymbolTable *symbols, Compound *out, Use use)
{
  return copy();
}

Id *Escape::findId(SymbolTable *symbols)
{
  return new Id();
}

/* ************************************************************************* */

Id * getRandomId(Type *type)
{
  static int r=0;
  std::string tstr = type->_toString(true);

  for (unsigned int i=0; i < tstr.length(); i++)
    if (!isalnum(tstr[i]) && tstr[i] != '_')
    {
      tstr = "__";
      break;
    }

  return new Id(type, CStr(tstr) << r++);
}
